#include "stdafx.h"
#include "LitEditorMeshSelecterDialog.h"

namespace Lit
{
	namespace Editor
	{
		MeshRenderScene::MeshRenderScene( const Lit::Color & bgcolor )
		{
			mTexture = Ogre::TextureManager::getSingleton().createManual( "EntityTex", 
					Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 
					256, 256, 0, Ogre::PF_A8R8G8B8 , Ogre::TU_RENDERTARGET );

			mRenderTex = mTexture->getBuffer()->getRenderTarget();
			mSceneMgr = Ogre::Root::getSingletonPtr()->createSceneManager("OctreeSceneManager", "EntityTexMgr");

			mLight = mSceneMgr->createLight("DisplayLight");
			mLight->setDirection(-1,-1,-1);
			mLight->setDiffuseColour(1,1,1);
			mLight->setType(Ogre::Light::LT_DIRECTIONAL);

			mCamera = mSceneMgr->createCamera("EntityCam");
			mCamera->setNearClipDistance(0.01F);
			mCamera->setFarClipDistance(0);
			mCamera->setAspectRatio(1);
			mCamera->setFOVy(Ogre::Degree(90));
			mCamera->setPosition(0,0,1);
			mCamera->lookAt(0,0,0);

			mViewport = mRenderTex->addViewport( mCamera );
			mViewport->setClearEveryFrame( true );
			mViewport->setBackgroundColour(bgcolor);

			mEntity = NULL;

		}
		MeshRenderScene::~MeshRenderScene()
		{
			mRenderTex->removeAllViewports();
			Ogre::Root::getSingletonPtr()->destroySceneManager(mSceneMgr);
			Ogre::Root::getSingletonPtr()->detachRenderTarget(mRenderTex->getName());
			Ogre::TextureManager::getSingletonPtr()->unload(mTexture->getName());
			Ogre::TextureManager::getSingletonPtr()->remove(mTexture->getName());
		}

		Lit::FilePath MeshRenderScene::createMeshSnapshot( const std::string &mesh )
		{
			if( Lit::Root::CacheManager()->isFileCached(mesh+".png", Lit::CL_PRE_RENDER, "mesh_previews") )
			{
				Ogre::LogManager::getSingleton().logMessage("Loading cached preview for '"+mesh+"'");
			}
			else
			{
				Ogre::LogManager::getSingleton().logMessage("Creating preview for '"+mesh+"'");
				if( Ogre::MeshManager::getSingleton().resourceExists( mesh+".mesh" ) ) mEntity = mSceneMgr->createEntity("scbDisplay", mesh+".mesh");
				else mEntity = mSceneMgr->createEntity("scbDisplay", mesh);
				mSceneMgr->getRootSceneNode()->attachObject(mEntity);

				Ogre::Vector3 vSize = mEntity->getBoundingBox().getHalfSize();
				Ogre::Vector3 vCenter = mEntity->getBoundingBox().getCenter(); 
   
				vSize += Ogre::Vector3(vSize.z, vSize.z, vSize.z);

				float maxsize = std::max(std::max(vSize.x,vSize.y),vSize.z);
   
				vSize = Ogre::Vector3(0, 0, maxsize * 1.1f) + vCenter;
   
				mCamera->setPosition(vSize.x,vSize.y,vSize.z);
				mCamera->lookAt(vCenter.x,vCenter.y,vCenter.z);
			
				mRenderTex->update();
				mRenderTex->writeContentsToFile( Lit::Root::CacheManager()->getCachePath(mesh+".png", Lit::CL_PRE_RENDER, "mesh_previews") );
			
				mEntity->detachFromParent();
				mSceneMgr->destroyEntity(mEntity);
			}
			mEntity = NULL;
			return Lit::Root::CacheManager()->getCachePath(mesh+".png", Lit::CL_PRE_RENDER, "mesh_previews");
		}

		MeshIconDatabase::MeshIconDatabase() : Initialiser("MeshIconDatabase"){}
		MeshIconDatabase::~MeshIconDatabase(){}

		void MeshIconDatabase::initialise( MeshCreationCallback cbk )
		{
			throwAlreadyInit();
			MeshRenderScene render;

			Lit::ResourcesListPtr list(Lit::Root::Instance().getResourcesList());
			size_t id = 0,
					sz = list->meshes().size();
		
			for( auto i=list->meshes().begin(); 
				i!= list->meshes().end(); 
				i++ )
			{
				std::string mesh = i->getName();
				if( !Ogre::StringUtil::endsWith(mesh,".mesh", false) ) mesh += ".mesh";
				try
				{
					mIcons[Ogre::StringUtil::replaceAll(mesh, ".mesh", "")] = render.createMeshSnapshot(mesh) ;
				}
				catch( std::exception& e )
				{
					LIT_LOG_DBG("error while trying to create preview for mesh '" +mesh+"':\r\n\t"+std::string(e.what()));
					mIcons[Ogre::StringUtil::replaceAll(mesh, ".mesh", "")] = FilePath(":/resources/exit.png");
				}
				catch( ... )
				{
					LIT_LOG_DBG("unknown error while trying to create preview for mesh '" +mesh+"'");
					mIcons[Ogre::StringUtil::replaceAll(mesh, ".mesh", "")] = FilePath(":/resources/exit.png");
				}
				cbk(mesh, id, sz);
				id ++;
			}
			setInitialised(true);
		}
		void MeshIconDatabase::shutdown( )
		{
			setInitialised(false);
		}
		void MeshIconDatabase::createMeshSnapshot( const std::string &mesh, MeshCreationCallback cbk )
		{
				MeshRenderScene render;
				mIcons[Ogre::StringUtil::replaceAll(mesh, ".mesh", "")] = render.createMeshSnapshot((!Ogre::StringUtil::endsWith(".mesh", false)?(mesh+".mesh"):mesh));
				Lit::Root::Instance().getResourcesList()->updateLists();
				cbk((!Ogre::StringUtil::endsWith(".mesh", false)?(mesh+".mesh"):mesh), 0, 1);
		}

		QIcon MeshIconDatabase::getIcon( const std::string &mesh )
		{
			throwNotInit();
			std::string mesh_ = Ogre::StringUtil::replaceAll( mesh, ".mesh", "" );
			for( auto i=mIcons.begin(); i!=mIcons.end(); i++ )
			{
				if( Ogre::StringUtil::replaceAll( i->first, ".mesh", "" ) == mesh_ )
				{
					QImage img( TO_QT(i->second) );
					return QIcon(QPixmap::fromImage(img));
				}
			}
			return QIcon();
		}
		
		void MeshSelecterDialog::prepareMeshList(const std::string &filter_)
		{
			ui.meshList->clear();
			ui.meshList->setIconSize( QSize(96,96) );
			ui.meshList->setViewMode( QListView::IconMode );
			std::string filter = filter_.empty()?"*":filter_;
			if( !Ogre::StringUtil::startsWith( filter, "*", false ) ) filter = "*"+filter;
			if( !Ogre::StringUtil::endsWith( filter, "*", false ) ) filter += "*";
			for( auto i=mResources->meshes().begin(); 
				i!= mResources->meshes().end(); 
				i++ )
			{
				std::string _mesh = i->getName();
				std::string mesh = Ogre::StringUtil::replaceAll( _mesh, ".mesh", "");
				if( filter.empty() || Ogre::StringUtil::match( _mesh, filter, false ) || Ogre::StringUtil::match( mesh, filter, false ) )
				{
					QIcon ico(MeshIconDatabase::Instance().getIcon(mesh));
					QListWidgetItem * itm = new QListWidgetItem(ico,TO_QT(mesh), ui.meshList);
					ui.meshList->addItem( itm );
				}
			}
		}

		MeshSelecterDialog::MeshSelecterDialog( QWidget* parent, Lit::ResourcesListPtr res ) 
			: QDialog( parent ), mResources(res)
		{ 
			ui.setupUi( this ); 
			connect( ui.meshList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(acceptSelection(QListWidgetItem*)) ); 
			connect( ui.searchFilters, SIGNAL(textChanged(const QString&)), this, SLOT(updateSearchFilters(const QString&)) );
		}
		MeshSelecterDialog::~MeshSelecterDialog( ){ }
		
		std::string MeshSelecterDialog::exec( const std::string &filter )
		{
			prepareMeshList(filter);
			int ans = 0;
			while( ((ans=QDialog::exec()) == QDialog::Accepted) && ui.meshList->selectedItems().isEmpty() )
			{
				QMessageBox::warning( this, "No selection", "You must select a mesh !" );
			}
			if( ans == QDialog::Accepted )
			{
				return FROM_QT( ui.meshList->currentItem()->text() )+".mesh";
			}
			return std::string( "" );
		}

		void MeshSelecterDialog::acceptSelection(QListWidgetItem*){
			accept();
		}
		void MeshSelecterDialog::updateSearchFilters(const QString &v){
			if( v.isEmpty() )
				ui.searchFilters->setText( "*" );
			else prepareMeshList(FROM_QT(v));
		}
	};
};